/*
 *  Kara IM - Kara Instant Messenger
 *  Copyright (C) 2007-2008 Markus Karnik
 *
 *  This program is free software; you can redistribute it and/or modify it 
 *  under the terms of the GNU General Public License as published by the
 *  Free Software Foundation; either version 3 of the License, 
 *  or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 *  for more details.
 *
 *  You should have received a copy of the GNU General Public License along 
 *  with this program; if not, see <http://www.gnu.org/licenses/>.
 *  
 */

package de.karnik.karaim;

import de.karnik.helper.LogFunctions;
import de.karnik.libkara.ImAccount;
import de.karnik.libkara.ImAccountManager;
import de.karnik.libkara.ImAccountManagerListener;
import de.karnik.libkara.pluginspecs.BaseProtocol;
import de.karnik.libkara.proto.xmpp.XmppSettings;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
import android.widget.Toast;
 
/**
 * This class implements the kara im service.
 * 
 * @author Markus Karnik - markus.karnik@my-design.org
 * @version 1.0
 * @since 1.0
 */
public class KaraIMService extends Service implements ImAccountManagerListener {

    /**
     * The notification manager object.
     */
    private NotificationManager notificationManager;
    /**
     * The account manager object.
     */
    private ImAccountManager accountManager = null;
    /**
     * The service intent object.
     */
    private Intent intent = null;
    /**
     * The service handler object.
     */
    private final Handler serviceHandler = new Handler();
    
    // notification and toasts
    
    /**
     * The toast id which indicates the toast to show.
     */
    private int toastID = 0;
    /**
     * The notification object.
     */
    private Notification statusNotification = null;
    /**
     * The notification ticker text.
     */
    private String tickerText = null;
    /**
     * The notification ticker expanded title.
     */
    private String expandedTitle = null;
    /**
     * The notification ticker expanded text.
     */
    private String expandedText = null;
    /**
     * The app icon id.
     */
    private int appIcon = 0;
    /**
     * The current status icon id.
     */
    private int statusIcon = 0;

    /**
     * Runnable to cancel the notification.
     */
    final Runnable cancelNotification = new Runnable() {
        public void run() {
        	cancelNotification();
        }
    }; 

    /**
     * Runnable to set the notification.
     */
    final Runnable setNotiftication = new Runnable() {
        public void run() {
        	setNotification();
        }
    }; 
    
    /**
     * Runnable to show a toast.
     */
    final Runnable showToast = new Runnable() {
        public void run() {
        	showToast();
        }
    };
    
    /**
     * Runnable to stop the whole application.
     */
    final Runnable stopSystem = new Runnable() {
        public void run() {
        	stopSystem();
        }
    };

    /**
     * Sets the notification with the current values.
     * 
     * @see #tickerText
     * @see #expandedText
     * @see #expandedTitle
     * @see #statusIcon
     * @see #statusNotification
     */
    private void setNotification() {
    	statusNotification = new Notification( this, statusIcon,  tickerText, 2, expandedTitle,
        		                               expandedText, null, appIcon,  getText( R.string.app_name ), null ); 
        notificationManager.notify( R.string.connection_status, statusNotification );
    }
    
    /**
     * Cancels the current notification.
     */
    private void cancelNotification() { 
        notificationManager.cancel( R.string.connection_status );
    }
    
    /**
     * Shows a toast with the current toast id.
     * 
     * @see #toastID
     */
    private void showToast() {
    	Toast.makeText( this, toastID, Toast.LENGTH_SHORT ).show();
    }
    
    /**
     * Stops the Kara IM application.
     */
    private void stopSystem() {
    	serviceHandler.post( cancelNotification );
    	this.stopSelf();
    }
    
    /* (non-Javadoc)
     * @see android.app.Service#onCreate()
     */
    @Override
    protected void onCreate() {
    	notificationManager = ( NotificationManager )getSystemService( NOTIFICATION_SERVICE );
    	
    	LogFunctions.log( "KaraIMService.onCreate", "initial log message" );
    	
        // This is who should be launched if the user selects our persistent
        // notification.
    	LogFunctions.log( "KaraIMService.onCreate", "create intent" );
        intent = new Intent();
        intent.setClass( this, KaraIM.class );

        tickerText = getText( R.string.status_disconnected ).toString();
        expandedTitle = getText( R.string.status_title ).toString();
        expandedText = getText( R.string.status_disconnected ).toString();
        appIcon = R.drawable.icon;
        statusIcon = R.drawable.icon_disconnected;
        
        this.serviceHandler.post( this.setNotiftication );
        
        
        LogFunctions.log( "KaraIMService.onCreate", "create settings" );
		XmppSettings settings = new XmppSettings();
		
        SharedPreferences sharedPrefs = getSharedPreferences( "androidKaraIM", MODE_WORLD_READABLE );
        Editor settingsEditor = sharedPrefs.edit();
        settingsEditor.commit();
		
		LogFunctions.log( "KaraIMService.onCreate", "settings created" );
		settings.putStringData( XmppSettings.STRING_VALUE_USERID, sharedPrefs.getString( "karaimUsername", "" ) );
		settings.putStringData( XmppSettings.STRING_VALUE_PASSWORD, sharedPrefs.getString( "karaimPassword", "" ) );
		settings.putStringData( XmppSettings.STRING_VALUE_SERVICEID, sharedPrefs.getString( "karaimServer", "jabber.org" ) );
		settings.putStringData( XmppSettings.STRING_VALUE_HOSTNAME, sharedPrefs.getString( "karaimServer", "jabber.org" ) );
		settings.putStringData( XmppSettings.STRING_VALUE_RESOURCEID, sharedPrefs.getString( "karaimResource", "Android" ) );
		settings.putBooleanData( XmppSettings.BOOLEAN_VALUE_CLIENT_TLS_ENABLED, sharedPrefs.getBoolean( "karaimTls", true ) );
		settings.putIntegerData( XmppSettings.INTEGER_VALUE_PORT, sharedPrefs.getInt( "karaimPort", 5222 ) );
		settings.putIntegerData( XmppSettings.INTEGER_VALUE_STATUS, BaseProtocol.STATUS_AVAILABLE );
        
		LogFunctions.log( "KaraIMService.onCreate", "create account manager" );
		this.accountManager = ImAccountManager.getInstance();
		this.accountManager.setManagerListener( this );
		
		LogFunctions.log( "KaraIMService.onCreate", "init account" );
		try {
			ImAccount account = null;
			account = new ImAccount( settings );
			account.setActive( true );
			this.accountManager.addAccount( account );
		} catch ( Exception e ) {
			LogFunctions.log( "KaraIMService.onCreate", "Exception", e.getMessage() );
			LogFunctions.log( "KaraIMService.onCreate", "Exception", e.getStackTrace() );
		}

    }
    
    /* (non-Javadoc)
     * @see android.app.Service#onStart(int, android.os.Bundle)
     */
    @Override
    protected void onStart( int startId, Bundle arguments ) {
    	super.onStart( startId, arguments );
    }
    
    
    
    /* (non-Javadoc)
     * @see android.app.Service#onDestroy()
     */
    @Override
    protected void onDestroy()  {
    	super.onDestroy();
    	LogFunctions.log( "KaraIMService.onDestroy", "destroy" );
    	notificationManager = null;
    	accountManager = null;
    	intent = null;
    	
    	System.exit( 0 );
    }

	/*
	public IBinder asBinder() {
		return mBinder;
	}*/
    
    /**
     * The IRemoteInterface is defined through IDL.
     */
    private final KaraIMServiceAIDL.Stub mBinder = new KaraIMServiceAIDL.Stub() {

		/* (non-Javadoc)
		 * @see de.karnik.karaim.KaraIMServiceAIDL#changeStatus(int)
		 */
		public void changeStatus( int status ) throws DeadObjectException {
	    	try {
	    		LogFunctions.log( "KaraIMServiceAIDL.changeStatus", "status change to", status );
				accountManager.changeStatus( status );
			} catch ( Exception e ) {
				LogFunctions.log( "KaraIMServiceAIDL.changeStatus", "Exception", e.getMessage() );
				LogFunctions.log( "KaraIMServiceAIDL.changeStatus", "Exception", e.getStackTrace() );
			}
			
		}

		/* (non-Javadoc)
		 * @see de.karnik.karaim.KaraIMServiceAIDL#stopSystem()
		 */
		public void stopSystem() throws DeadObjectException {
			serviceHandler.post( stopSystem );
		}
    };

    
	/* (non-Javadoc)
	 * @see de.karnik.libkara.ImAccountManagerListener#connectionTaskEnded()
	 */
	public void connectionTaskEnded() {
		
		LogFunctions.log( "KaraIMService.connectionTaskEnded", "connection task ended" );
		
		toastID = R.string.msg_connected;
		serviceHandler.post( showToast );
		
        tickerText = getText( R.string.status_connected ).toString();
        expandedTitle = getText( R.string.status_title ).toString();
        expandedText = getText( R.string.status_connected ).toString();
        appIcon = R.drawable.icon;
        statusIcon = R.drawable.icon_connected;
        
        this.serviceHandler.post( this.setNotiftication );
		
	}

	/* (non-Javadoc)
	 * @see de.karnik.libkara.ImAccountManagerListener#connectionTaskStarted()
	 */
	public void connectionTaskStarted() {
		LogFunctions.log( "KaraIMService.connectionTaskStarted", "connection task started" );
		
		toastID = R.string.msg_connecting;
		serviceHandler.post( showToast );
	}

	/* (non-Javadoc)
	 * @see de.karnik.libkara.ImAccountManagerListener#connectionDisconnected()
	 */
	public void connectionDisconnected() {
		
		LogFunctions.log( "KaraIMService.connectionDisconnected", "connection disconnected" );
		toastID = R.string.msg_disconnected;
		serviceHandler.post( showToast );
		
        tickerText = getText( R.string.status_disconnected ).toString();
        expandedTitle = getText( R.string.status_title ).toString();
        expandedText = getText( R.string.status_disconnected ).toString();
        appIcon = R.drawable.icon;
        statusIcon = R.drawable.icon_disconnected;
        
        this.serviceHandler.post( this.setNotiftication );
	}
	
	/* (non-Javadoc)
	 * @see de.karnik.libkara.ImAccountManagerListener#statusChanged()
	 */
	public void statusChanged() {}

	/* (non-Javadoc)
	 * @see android.app.Service#onBind(android.content.Intent)
	 */
	@Override
	public IBinder onBind( Intent intent ) {
		return mBinder;
	}

}
